package mybatisgen.plugin;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.internal.util.JavaBeansUtil;

import java.util.List;
import java.util.Optional;

/**
 * @className: com.xinmei.mybatisgen.plugin.ExampleEnhancedPlugin
 * @description: 
 * @author gdw
 * @date 2019-01-04 11:43:29
 */
public class ExampleEnhancedPlugin extends PluginAdapter {
    @Override
    public boolean validate(List<String> warnings) {
        return true;
    }

    @Override
    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        addOrderByCriteria(topLevelClass, introspectedTable);
        return true;
    }

    public static String getMethodName(String property) {
        StringBuilder sb = new StringBuilder();
        sb.append(property);
        if (Character.isLowerCase(sb.charAt(0))) {
            if (sb.length() == 1 || !Character.isUpperCase(sb.charAt(1))) {
                sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
            }
        }
        return sb.toString();
    }

    private void addOrderByCriteria(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        // 生成内部枚举
        InnerClass orderByCriteriaInnerClass = new InnerClass(new FullyQualifiedJavaType("OrderByCriteria"));
        orderByCriteriaInnerClass.setVisibility(JavaVisibility.PUBLIC);
        orderByCriteriaInnerClass.setStatic(true);
        topLevelClass.addInnerClass(orderByCriteriaInnerClass);

        // 排序字段
        Field orderByField = new Field("orderByClause", new FullyQualifiedJavaType(StringBuilder.class.getName()));
        orderByField.setVisibility(JavaVisibility.PRIVATE);
        orderByField.setFinal(true);
        orderByCriteriaInnerClass.addField(orderByField);

        // 创建构造器
        Method constructor = new Method("OrderByCriteria");
        constructor.setConstructor(true);
        constructor.setVisibility(JavaVisibility.PUBLIC);
        constructor.addParameter(new Parameter(new FullyQualifiedJavaType(StringBuilder.class.getName()), "orderByClause"));
        constructor.addBodyLine("this.orderByClause = orderByClause;");
        FormatTools.addMethodWithBestPosition(orderByCriteriaInnerClass, constructor);

        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
            Field field = JavaBeansUtil.getJavaBeansField(introspectedColumn, context, introspectedTable);
            // 顺序排序方法
            Method orderByMethod = new Method("orderBy" + getMethodName(field.getName()));
            orderByMethod.setVisibility(JavaVisibility.PUBLIC);
            orderByMethod.setReturnType(orderByCriteriaInnerClass.getType());
            orderByMethod.addBodyLine("appendOrderByClause(\"" + introspectedColumn.getActualColumnName() + "\");");
            orderByMethod.addBodyLine("return this;");
            FormatTools.addMethodWithBestPosition(orderByCriteriaInnerClass, orderByMethod);

            // 逆序排序方法
            Method orderByDescMethod = new Method("orderBy" + getMethodName(field.getName()) + "Desc");
            orderByDescMethod.setVisibility(JavaVisibility.PUBLIC);
            orderByDescMethod.setReturnType(orderByCriteriaInnerClass.getType());
            orderByDescMethod.addBodyLine("appendOrderByClause(\"" + introspectedColumn.getActualColumnName() + " DESC\");");
            orderByDescMethod.addBodyLine("return this;");
            FormatTools.addMethodWithBestPosition(orderByCriteriaInnerClass, orderByDescMethod);
        }

        // 创建方法
        Method orderByMethod = new Method("appendOrderByClause");
        orderByMethod.setVisibility(JavaVisibility.PRIVATE);
        orderByMethod.addParameter(new Parameter(FullyQualifiedJavaType.getStringInstance(), "clause"));
        orderByMethod.addBodyLine("if(orderByClause.length() > 0){");
        orderByMethod.addBodyLine("orderByClause.append(',').append(clause);");
        orderByMethod.addBodyLine("}else{");
        orderByMethod.addBodyLine("orderByClause.append(clause);");
        orderByMethod.addBodyLine("}");
        FormatTools.addMethodWithBestPosition(orderByCriteriaInnerClass, orderByMethod);

        // 逆序排序方法
        Method orderByDescMethod = new Method("createOrderByCriteria");
        orderByDescMethod.setVisibility(JavaVisibility.PUBLIC);
        orderByDescMethod.setReturnType(orderByCriteriaInnerClass.getType());
        orderByDescMethod.addBodyLine("StringBuilder orderByClause = new StringBuilder();");
        orderByDescMethod.addBodyLine("this.orderByClause = orderByClause;");
        orderByDescMethod.addBodyLine("OrderByCriteria orderByCriteria = new OrderByCriteria(orderByClause);");
        orderByDescMethod.addBodyLine("return orderByCriteria;");
        topLevelClass.addMethod(orderByDescMethod);

        // 修改orderByClause的参数类型
       Optional<Field> orderByClauseFiled = topLevelClass.getFields().stream().filter(f -> f.getName().equals("orderByClause")).findAny();
       orderByClauseFiled.get().setType(new FullyQualifiedJavaType(CharSequence.class.getName()));

        // 修改getOrderByClause方法
        Optional<Method> getOrderByClauseMethod = topLevelClass.getMethods().stream().filter(f -> f.getName().equals("getOrderByClause")).findAny();
        getOrderByClauseMethod.get().getBodyLines().clear();
        getOrderByClauseMethod.get().getBodyLines().add("return this.orderByClause == null ? null : this.orderByClause.toString();");
    }
}
